﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace ConversionInterface
{
    public class MediaInfo
    {
        private List<MediaFile> mediaFiles = new List<MediaFile>();

        public MediaInfo()
        {

        }

        public MediaFile AddFile(string filename, int index)
        {
            FileInfo fileInfo = new FileInfo(filename);
            if (!fileInfo.Exists)
                throw new ArgumentException(filename + " does not exist");


            ProcessStartInfo startInfo = new ProcessStartInfo("MediaInfo.exe", filename);
            startInfo.RedirectStandardError = true;
            startInfo.RedirectStandardInput = true;
            startInfo.RedirectStandardOutput = true;
            startInfo.CreateNoWindow = true;
            startInfo.UseShellExecute = false;
            Process process = new Process();

            process.StartInfo = startInfo;
            process.EnableRaisingEvents = true;
            
            MediaFile file = null;

            if (process.Start())
            {
                file = new MediaFile(filename);
                StreamReader error = process.StandardError;
                StreamReader output = process.StandardOutput;
                StreamWriter input = process.StandardInput;
                ParseResults(output.ReadToEnd(),file);
                this.mediaFiles.Add(file);
            }

            return file;
        }

        private void ParseResults(string results, MediaFile file)
        {
            string[] lines = results.Split(new string[] { "\r\r\n\r\r\n" },StringSplitOptions.None);
            List<Dictionary<string,string>> audio = new List<Dictionary<string,string>>();
            List<Dictionary<string,string>> subs = new List<Dictionary<string,string>>();
            Dictionary<string, string> general = null;
            Dictionary<string, string> video = null;
            int track = 1;

            foreach (string s in lines)
            {
                if (s.StartsWith("General"))
                {
                    general = GetDictionary(s);
                }
                else if (s.StartsWith("Video"))
                {
                    video = GetDictionary(s);
                    
                }
                else if (s.StartsWith("Audio"))
                {
                    audio.Add(GetDictionary(s));
                }
                else if (s.StartsWith("Text"))
                {
                    subs.Add(GetDictionary(s));
                }
            }

            DecipherGeneral(general, file);
            DecipherVideo(video, file);
            DecipherAudio(audio, file);
            DecipherSubs(subs, file);

            file.Video.TrackNumber = track++;
            foreach (AudioTrack audioTrack in file.Audio)
                audioTrack.TrackNumber = track++;
            foreach (SubtitleTrack subTrack in file.Subs)
                subTrack.TrackNumber = track++;
        }

        private void DecipherGeneral(Dictionary<string, string> general, MediaFile file)
        {
            if (general == null)
                throw new ArgumentException("No information about media file found");

            string type = general["Format"];
            switch (type)
            {
                case "Matroska":
                    file.Type = MediaFile.MediaType.MKV;
                    break;
                default:
                    throw new ArgumentException("Unsupported file type: " + type);
            }

        }

        private void DecipherVideo(Dictionary<string, string> video, MediaFile file)
        {
            if (video == null)
                throw new ArgumentException("No video found");

            string format = video["Format"];
            switch (format)
            {
                case "AVC":
                    file.Video.Codec = VideoTrack.VideoCodec.H264;
                    file.Video.Type = VideoTrack.FileType.MP4;
                    break;
                default:
                    throw new ArgumentException("Unsupported video codec: " + format);
            }


            string bitrate = video["Nominal bit rate"].Replace("Kbps","").Trim();
            string width = video["Width"].Replace("pixels", "").Trim();
            string height = video["Height"].Replace("pixels", "").Trim();
            string aspect = video["Display aspect ratio"];
            string fps = video["Frame rate"].Replace("fps","").Trim();
            file.Video.BitRate = Convert.ToInt32(bitrate);
            file.Video.Width = Convert.ToInt32(width);
            file.Video.Height = Convert.ToInt32(height);
            file.Video.AspectRatio = aspect;
            file.Video.FPS = Convert.ToDecimal(fps);
         
            
        }

        private void DecipherAudio(List<Dictionary<string, string>> audio, MediaFile file)
        {
            if (audio.Count == 0)
                throw new ArgumentException("No audio found");

            foreach (Dictionary<string, string> d in audio)
            {
                AudioTrack track = new AudioTrack();
                string format = d["Format"];
                string language = d["Language"];

                switch (format)
                {
                    case "AAC":
                        track.Codec = AudioTrack.AudioCodec.AAC;
                        break;
                    case "MPEG Audio":
                        track.Codec = AudioTrack.AudioCodec.MPEG;
                        break;
                    case "Vorbis":
                        track.Codec = AudioTrack.AudioCodec.Vorbis;
                        break;
                    default:
                        throw new ArgumentException("Audio Codec Not Supported: " + format);
                }

                switch (language)
                {
                    case "English":
                        track.Language = MediaFile.MediaLanguage.English;
                        break;
                    case "French":
                        track.Language = MediaFile.MediaLanguage.French;
                        break;
                    case "Japanese":
                        track.Language = MediaFile.MediaLanguage.Japanese;
                        break;
                    case "Spanish":
                        track.Language = MediaFile.MediaLanguage.Spanish;
                        break;
                    default:
                        track.Language = MediaFile.MediaLanguage.Undefined;
                        break;
                }

                file.Audio.Add(track);
            }
        }

        private void DecipherSubs(List<Dictionary<string, string>> subs, MediaFile file)
        {
            if (subs.Count == 0)
                return;

            foreach (Dictionary<string, string> d in subs)
            {
                SubtitleTrack track = new SubtitleTrack();
                string format = d["Format"];
                string language = d["Language"];
                switch (format)
                {
                    case "ASS":
                        track.Type = SubtitleTrack.SubtitleType.ASS;
                        break;
                    default:
                        throw new ArgumentException("Subtitle Type Not Supported: " + format);
                }

                switch (language)
                {
                    case "English":
                        track.Language = MediaFile.MediaLanguage.English;
                        break;
                    case "French":
                        track.Language = MediaFile.MediaLanguage.French;
                        break;
                    case "Japanese":
                        track.Language = MediaFile.MediaLanguage.Japanese;
                        break;
                    case "Spanish":
                        track.Language = MediaFile.MediaLanguage.Spanish;
                        break;
                    default:
                        track.Language = MediaFile.MediaLanguage.Undefined;
                        break;
                }
                file.Subs.Add(track);
            }

        }

        private Dictionary<string,string> GetDictionary(string wholeSection)
        {
            string[] section = wholeSection.Split(new string[] { "\r\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            Dictionary<string, string> d = new Dictionary<string, string>();
            foreach (string s in section)
            {
                if (s.IndexOf(":") > 0)
                {
                    string[] pieces = s.Split(new char[] {':'},2);
                    if (pieces.Length == 2)
                    {
                        d.Add(pieces[0].Trim(), pieces[1].Trim());
                    }
                }
            }
            return d;
        }

        public List<MediaFile> MediaFiles
        {
            get { return mediaFiles; }
        }
    }
}
